#include <TabLite.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

extern int TabElemClearValue(TabElem* elem);

TabLite* TabLiteNew()
{
    TabLite* tab = malloc(sizeof(TabLite));
    if (!tab)
    {
        TabErrorSet(TAB_ERROR_NOMEM); 
        return NULL;
    }
    tab->next = NULL;
    memset(tab->elems, 0, sizeof(TabElem) * TAB_ELEM_NR);
    TabErrorSet(TAB_ERROR_OK);
    return tab;
}

int TabLiteDel(TabLite* tab)
{
    if (!tab)
    {
        TabErrorSet(TAB_ERROR_ARG); 
        return -1;        
    }
    TabElem* tmp;
    ForEachTabElem(tab, tmp)
    {
        if (tmp->tag != TAB_TAG_NIL)
        {
            if (TabElemClearValue(tmp) < 0)
                return -1;
        }
    }
    TabLite* tabNext = tab->next;
    tab->next = NULL;
    free(tab);

    if (!tabNext)   /* no next, del finish */
    {
        TabErrorSet(TAB_ERROR_OK);
        return 0;
    }
    return TabLiteDel(tabNext);
}

// BKDR Hash Function
unsigned int TabLiteBKDRHash(char *str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
    unsigned int hash = 0;
    while (*str)
    {
        hash = hash * seed + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}

static int TabLiteCollisionDetection(TabLite* parent, TabLite* child)
{
    TabElem* elemP;
    TabElem* elemC;
    elemP = TabLiteGetByNext(parent, NULL);
    while (elemP != NULL)
    {
        elemC = TabLiteGetByNext(child, NULL);
        while (elemC != NULL)
        {
            if (elemP->hashKey == elemC->hashKey)
            {
                TabErrorSet(TAB_ERROR_FAULT);
                return 1;   /* has collision */
            }
            elemC = TabLiteGetByNext(child, elemC);    
        }
        elemP = TabLiteGetByNext(parent, elemP);    
    }
    return 0;   /* no collision */
}

int TabLiteAttach(TabLite* parent, TabLite* child)
{
    if (!parent || !child)
    {
        TabErrorSet(TAB_ERROR_ARG); 
        return -1;
    }
    /* TODO: check table elem name same? */
    if (TabLiteCollisionDetection(parent, child))
        return -1;
    while (parent->next != NULL)    /* get the last parent */
    {
        parent = parent->next;
    }
    parent->next = child;
    TabErrorSet(TAB_ERROR_OK);
    return 0;
}

int TabLiteDetach(TabLite* parent, TabLite* child)
{
    if (!parent || !child)
    {
        TabErrorSet(TAB_ERROR_ARG); 
        return -1;        
    }
    while (parent->next != NULL)    /* get the last parent */
    {
        if (parent->next == child)  /* next is child */
        {
            parent->next = NULL;
            TabErrorSet(TAB_ERROR_OK);
            return 0;
        }
    }
    TabErrorSet(TAB_ERROR_NOFOUND); 
    return -1;
}

void TabLiteDump(TabLite* tab)
{
    if (!tab)
    {
        TabErrorSet(TAB_ERROR_ARG); 
        return;
    }
    printf("====TabLite Start====\n");
    TabElem* tmp;
    ForEachTabElem(tab, tmp)
    {
        TabElemDump(tmp);
    }
    printf("====TabLite End====\n");   
    TabLiteDump(tab->next);
}